package com.annet.token.utils;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import lombok.extern.slf4j.Slf4j;

import java.io.UnsupportedEncodingException;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * Json web token 操作
 *
 * @author djb
 * @date 2018/8/31
 */
@Slf4j
public final class JwtTokenUtils {

    /**
     * token秘钥，请勿泄露，请勿随便修改
     */
    public static final String SECRET = "E10ADC3949BA59ABBE56E057F20F883E";
    /**
     * token 过期时间: 7天
     */
    public static final int calendarField = Calendar.DAY_OF_YEAR;
    public static final int calendarInterval = 7;

    /**
     * JWT生成Token.<br/>
     * <p>
     * JWT构成: header, payload, signature
     *
     * @param userId 登录成功后用户userId, 参数userId不可传空
     */
    public static String createToken(String userId) {

        Date iatDate = new Date();
        // expire time
        Calendar nowTime = Calendar.getInstance();
//        nowTime.add(calendarField, calendarInterval);
        nowTime.add(Calendar.SECOND, calendarInterval);
        Date expiresDate = nowTime.getTime();

        // header Map
        Map<String, Object> map = new HashMap<>();
        map.put("alg", "HS256");
        map.put("typ", "JWT");

        // build token
        // param backups {iss:Service, aud:APP}
        String token = null; // signature
        try {
            token = JWT.create()
                    .withHeader(map) // header
                    .withClaim("iss", "Service") // payload
                    .withClaim("aud", "ANNET")
                    .withClaim("userId", userId == null ? "" : userId)
                    .withIssuedAt(iatDate) // sign time
                    .withExpiresAt(expiresDate) // expire time
                    .sign(Algorithm.HMAC256(SECRET));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return token;
    }

    /**
     * 解密Token
     *
     * @param token
     * @return
     * @throws Exception
     */
    public static Map<String, Claim> verifyToken(String token) {
        DecodedJWT jwt;
        try {
            JWTVerifier verifier = JWT.require(Algorithm.HMAC256(SECRET)).build();
            jwt = verifier.verify(token);
        } catch (Exception e) {
            log.info("无效的token");
            // token 校验失败, 抛出Token验证非法异常
            return null;
        }
        return jwt.getClaims();
    }

    /**
     * 根据 Token 获取 userId
     *
     * @param token
     * @return user_id
     */
    public static String getUserId(String token) {
        Map<String, Claim> claims = verifyToken(token);
        if (null == claims) {
            return null;
        }
        Claim user_id_claim = claims.get("userId");
        if (null == user_id_claim || Strings.isEmpty(user_id_claim.asString())) {
            // token 校验失败, 抛出Token验证非法异常
            log.info("无效的token: " + token);
            return null;
        }
        return user_id_claim.asString();
    }

    /**
     * 解密Token
     *
     * @param token
     * @param secretKey
     * @return
     * @throws Exception
     */
    public static Map<String, Claim> verifyToken(String token,String secretKey) {
        DecodedJWT jwt;
        try {
            JWTVerifier verifier = JWT.require(Algorithm.HMAC256(secretKey)).build();
            jwt = verifier.verify(token);
        } catch (Exception e) {
            log.info("无效的token");
            // token 校验失败, 抛出Token验证非法异常
            return null;
        }
        return jwt.getClaims();
    }

    public static void main(String[] args) {
        String token = createToken("P95014");
        long st = System.currentTimeMillis() + (1000000 * 60 * 1000L);
        System.out.println("token=" + token);
        System.out.println("timestamp=" + st);
        String stringA = "token=" + token + "&timestamp=" + st;
        String sign = MD5Utils.getMD5(stringA).toUpperCase();
        System.out.println("sign=" + sign);

    }

}
